package service;

import dao.QiziDao;
import dao.UserDao;
import pojo.*;

import java.io.IOException;
import java.util.*;

public class GameService {
    /*
           棋盘:
       map[i][j]表示坐标(i,j)的值
       0表示空地
       其余数字表示棋子id
    */
    private static int map[][]=new int[15][15];
    private static Stack<Integer> saveStep=new Stack<>(); //人人对战悔棋 栈保存下棋位置 x*15+y
    private static int flag=0; //偶数表示玩家1落子  奇数表示玩家2或者AI落子
    private static Player player1=null;
    private static Player player2=null;
    private static AI ai=null;
    private static boolean sign=false; //false代表选择的是人机模式 true代表选择的是人人模式

    public static Player getPlayer1() {
        return player1;
    }

    public static Player getPlayer2() {
        return player2;
    }

    public static AI getAi() {
        return ai;
    }

    public static int[][] getMap() {
        return map;
    }

    /*
          功能：现在的用户下过棋没有
          参数：void
          返回值：true代表下过棋
                 false代表没下过棋
          */
    public static boolean havePlay() {
        return saveStep.size()>=2;
    }

    /*
              功能：现在是谁在下棋
              参数：void
              返回值：返回0 代表玩家1在下棋
                     返回1 代表玩家2/ai在下棋
              */
    public static int whoTurn() {
        return flag%2;
    }

    /*
      功能：切换到对方下棋
      参数：void
      返回值：void

     */
    public static void changeSide() {
        flag++;
    }


    /*
     功能：将玩家1/玩家2指向player对象
     参数：player要指向的对象
          who 1代表让player1指向player 2代表让player2指向player
     返回值：void
     */
    public static void setPlayer(Player player,int who) {
        if(who==1) player1=player;
        else if(who==2) player2=player;
    }

    /*
    功能：根据账号名返回对应的Player对象
    参数：name 要查找的账号名
    返回值：返回Player对象
    */
    public static Player findPlayerService(String name) {
        return UserDao.findPlayer(name);
    }

    /*
     功能：根据棋子id返回对应的Chess对象
     参数：id 要查找的棋子id
     返回值：返回Chess对象
    */
    public static Chess findQiziService(int id) {
        return QiziDao.findQizi(id);
    }

    /*
        编号：1
        难度：简单
        负责人：123
        功能：根据谁胜利来修改对象的属性 调用dao层changePlayer方法修改文件
               根据sign判断是人人还是人机
               判断n是哪方赢 修改对象的属性
               [人机胜利数 人机失败数 人人胜利数 人人失败数 金币]

        参数：n代表谁胜利 1玩家1胜利 2玩家2/ai胜利
             money代表这局赌的钱数
        返回值：void
     */
    public static void changePlayerService(int n,int money) {
        if (sign){
            //人人模式
            if (n == 1){
                player1.setWithPlayerWin(player1.getWithPlayerWin() + 1);
                player1.setMoney(player1.getMoney() + money);
                player2.setWithPlayerLose(player1.getWithPlayerLose() + 1);
                UserDao.changePlayer(player1);
                UserDao.changePlayer(player2);
            }
            if (n == 2){
                player2.setWithPlayerWin(player2.getWithPlayerWin() + 1);
                player2.setMoney(player2.getMoney() + money);
                player1.setWithPlayerLose(player1.getWithPlayerLose() + 1);
                UserDao.changePlayer(player1);
                UserDao.changePlayer(player2);
            }
        }else {
            //人机模式
            if (n == 1){
                player1.setWithAIWin(player1.getWithAIWin() + 1);
                player1.setMoney(player1.getMoney() + money);
                UserDao.changePlayer(player1);
            }
            if (n == 2){
                player1.setWithAILose(player1.getWithAILose() + 1);
                player1.setMoney(player1.getMoney() - money);
                UserDao.changePlayer(player1);
            }
        }
    }

    /*
    编号：2
    难度：简单
    负责人：123
    功能：将注册的账号写到文件[users]中
        创建一个新的Player对象，调用Player(String name,String pwd)方法
        调用insertPlayer(pojo.Player p)方法写入文件中
    参数：name 新创建的账户名
         pwd 新创建的账户的密码
    返回值：void
 */
    public static void register(String name,String pwd) throws IOException {
        Player player = new Player(name,pwd);
        UserDao.insertPlayer(player);
    }

    /*
    编号：3
    难度：简单
    负责人：123
    功能：判断此账户是否合法
        合法：文件中存在(调用dao层方法) 且与用户1不是同用户
    参数：name 用户2的账户名
         pwd 用户2的账户密码
    返回值：true 合法
            false 不合法
     */
    public static boolean loginIsLegal(String name,String pwd) {
        Player player = UserDao.findPlayer(name); //通过用户2的账号名name 得到用户2对象
        if(player==null) return false; //用户2为空，不存在此账号 登录不合法 return false
        if(!player.getPwd().equals(pwd)) return false; //密码不一致 return false
        if(player==player1) return false; //用户2和用户1是同用户 登录不合法 return false
        return true;
    }

    /*
    编号：4
    难度：简单
    负责人：123
    功能：得到当前用户的所有棋子id和对应颜色
    参数：who 传入1代表用户1的所有棋子，传入2代表用户2的所有棋子
    返回值：Map<Integer,String>
    */
    public static Map<Integer,String> getAllqizi(int who) {
        Map<Integer, String> map = new HashMap<>();
        if (who == 1){
            List<Integer> totalChess = player1.getTotalChess();
            for (int i = 1; i <= totalChess.size(); i++) {
                Chess qizi = QiziDao.findQizi(i);
                map.put(i,qizi.getStyle());
            }
        }else {
            List<Integer> totalChess = player2.getTotalChess();
            for (int i = 1; i <= totalChess.size(); i++) {
                Chess qizi = QiziDao.findQizi(i);
                map.put(i,qizi.getStyle());
            }
        }
        return map;
    }

    /*
        编号：5
        难度：简单
        负责人：123
        功能：初始化人机对战时的游戏数据
             map全为0
             flag为0
             sign为false
             player1的属性[现在在用的棋子chess]赋值为用户选择的棋子id
             chess=随机一个棋子的id，不能是现在传入的id
             创建ai对象 ai=new AI(15,1,chess,difficult)
        参数：id 用户选择的棋子id
             difficult 用户选择的难度
        返回值：void
     */
    public static void initWithAI(int id,int difficult) {
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                map[i][j] = 0;
            }
        }
        flag = 0;
        sign = false;
        player1.setChess(id);
        Random random = new Random();
        int aiId = 0;
        List<Chess> allQizi = QiziDao.getAllQizi();
        int round=allQizi.size();
        while (true) {
            aiId = random.nextInt(round+1);
            if (aiId != id&&aiId!=0){
                break;
            }
        }
        if(difficult==1){
            ai=new AI1(15,1,aiId,0);//只会防守
        }else if(difficult==2){
            ai=new AI1(15,1,aiId,1);//攻击进攻都考虑
        }else{
            ai=new AI2(15,1,aiId,2);//算2步棋
        }

    }

    /*
        编号：6
        难度：简单
        负责人：123
        功能：初始化人人对战时的游戏数据
             map全为0
             flag为0/1 为whoFirst的值
             saveStep清空
             sign为true
             player1的属性[现在在用的棋子chess]赋值为用户选择的棋子id1
                      属性[regret现在悔棋次数]清0
             player2的属性[现在在用的棋子chess]赋值为用户选择的棋子id2
                      属性[regret现在悔棋次数]清0
        参数：id1用户1选择的棋子
             id2用户2选择的棋子
             whoFirst谁先下 0为玩家1 1为玩家2
        返回值：void
     */
    public static void initWithPlayer(int id1,int id2,int whoFirst) {
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                map[i][j] = 0;
            }
        }
        flag = whoFirst;
        saveStep.clear();
        sign = true;
        player1.setChess(id1);
        player1.setRegret(0);
        player2.setChess(id2);
        player2.setRegret(0);
    }

    /*
        编号：7
        难度：一般
        负责人: 今天
        功能: 在指定位置落子
            如果map[x][y]是空地(为0) 则修改map[x][y]的值
                改为相应棋子id
                    根据sign判断是什么模式
                        人机模式
                            (根据flag判断是player1/ai在下棋 棋子id属性chess)
                        人人模式
                            (根据flag判断是player1/player2在下棋 棋子id属性chess)
               在stack中保存下棋位置
            否则不操作
        参数:
            x: 当前回合落子的x坐标
            y: 当前回合落子的y坐标
        返回值:
            0表示落子失败 (棋盘已经有子)
            1表示落子成功

    */
    public static int playerMove(int x, int y){
        //如果为空地
        if(map[x][y]==0){
            if(flag%2==0){
                //偶数,玩家1落子
                map[x][y]=player1.getChess();
            }else{
                //奇数,玩家2/ai落子
                if(sign){
                    //人人模式
                    map[x][y]=player2.getChess();
                }else{
//                    人机模式
                    map[x][y]=ai.getChess();
                }
            }
            saveStep.push(x*15+y);
            return 1;
        }
        return 0;
    }


    /*
        编号：8
        难度：一般
        负责人: 今天
        功能: 根据传入的坐标(map对应位置),flag和sign 判断落点后是否获胜
        参数:
            x: 当前回合落子的x坐标
            y: 当前回合落子的y坐标
        返回值:
            0表示没有获胜
            1表示player1胜利
            2表示player2/ai胜利
    */
    public static int isWin(int x,int y){
        int[][] dir = {
                // x起始  y起始  x移动方向  y移动方向
                {0, -4, 0, 1},  // 从上往下
                {-4, -4, 1, 1}, // 从左上 往右下
                {-4, 0, 1, 0},  // 从左往右
                {-4, 4, 1, -1}  // 从左下 往右上
        };
        int count;
        for (int i = 0; i < 4; i++) {
            count = 0;
            //从起始点开始循环  一直循环到终点  也就是从上往下 从左上往右下 从左往右  从左下往右上
             /*
                  j和k 分别表示起始点相对的x位置和y位置
             比如从上往下判断 则起始相对位置是(0,-4) x每次+0  y每次+1  循环9次
             map[x+j][y+k] 表示当前判断的位置
                   比如要判断(5,6)从上往下(每次循环x+0,y+1)
                  则是从(5,6-4)开始往下移动  一路到(5,6+4)
             */
            for (int j = dir[i][0], k = dir[i][1], n = 0;
                 n < 9;
                 j += dir[i][2], k += dir[i][3], n++) {
                //如果超过棋盘 直接下一次循环
                if (x + j >= 15 || y + k >= 15 || x + j < 0 || y + k < 0)
                    continue;
                //如果是当前玩家的子 则count+1
                if (map[x + j][y + k] == map[x][y]) {
                    if (count == 4) return (flag % 2) + 1;
                    count++;
                }
                //否则 count = 0  重新计数
                else {
                    count = 0;
                }
            }
        }
        return 0;
    }

    /*
        编号：9
        难度：简单
        负责人：今天
        功能：悔棋，stack弹出两个坐标还原为空地
              修改悔棋对象的悔棋次数属性(根据flag判断)
              修改悔棋对象的金币数+regretCost
              修改另一方对象的金币数-regretCost
        参数：regretCost 悔棋要花费的钱数
        返回值：void
     */
    public static void regret(int regretCost) {
        int temp=saveStep.pop();
        int x=temp/15;
        int y=temp%15;
        map[x][y]=0;

        temp=saveStep.pop();
        x=temp /15;
        y=temp%15;
        map[x][y]=0;
        // 修改悔棋次数
        if (flag % 2 == 0) {
            // 玩家 1 悔棋
            player1.setRegret(player1.getRegret()+1);
            player1.setMoney(player1.getMoney()-regretCost);
            player2.setMoney(player2.getMoney()+regretCost);
            UserDao.changePlayer(player1);
            UserDao.changePlayer(player2);
        } else {
            // 玩家 2 悔棋
            player2.setRegret(player2.getRegret()+1);
            player2.setMoney(player2.getMoney()-regretCost);
            player1.setMoney(player1.getMoney()+regretCost);
            UserDao.changePlayer(player1);
            UserDao.changePlayer(player2);
        }
    }

    /*
   编号：10
       难度：简单
       负责人：李季岭
       功能：
        按人人战对胜利数进行降序排行
   调用UserDao的getAllPlayers()方法得到集合,按人人对战胜利数进行降序排序
       参数：void
       返回值：List<Player>

    */
    public static List<Player> getWithPlayerWinlist(){
        List<Player> players= UserDao.getAllPlayers();
        players.sort(( o1,  o2)-> {return o2.getWithPlayerWin()-o1.getWithPlayerWin();});
        return players;
    }
    /*
    编号：11
        难度：简单
        负责人：李季岭
        功能：
        按金币数进行降序排行
    调用UserDao的getAllPlayers()方法得到集合,按金币数进行降序排序
        参数：void
        返回值：List<Player>
     */
    public static List<Player> getMoneyList(){
        List<Player> players=UserDao.getAllPlayers();
        players.sort((o1,o2)->{return o2.getMoney()-o1.getMoney();});
        return players;
    }

    /*
     编号：12
     难度：简单
     负责人：李季岭
     功能：调用QiziDao的方法，获取全部qizi集合，并按照价格低到高排序
     * 参数：void
     * 返回值：List<Chess>
     */
    public static List<Chess> ShopSortService(){
        List<Chess> players= QiziDao.getAllQizi();
        players.sort((o1,o2)->{return o1.getPrice()-o2.getPrice();});
        return players;
    }

    /*
     编号：13
     难度：简单
     负责人：今天
     功能：
        支持玩家购买商品，调用相应方法处理扣除金币和物品发放
        当前用户(player1)的金币数更新 减去棋子的价格
        当前用户(player1)的拥有棋子list更新 增加当前id当集合中
        调用dao层修改文件
     * 参数：要购买的棋子id
     * 返回值：void
     */
    public static void ShopService(int id){
        //当前用户(player1)的金币数更新 减去棋子的价格
        player1.setMoney(player1.getMoney()-QiziDao.findQizi(id).getPrice());
        //当前用户(player1)的拥有棋子list更新 增加当前id当集合中
        List<Integer> totalChess = player1.getTotalChess();
        totalChess.add(id);
        player1.setTotalChess(totalChess);
        UserDao.changePlayer(player1);
    }


}
